import json

from django.http import JsonResponse
from django.shortcuts import render

# Create your views here.
from django.views import View
from rest_framework.decorators import action
from rest_framework.filters import OrderingFilter
from rest_framework.response import Response

from rest_framework.views import APIView

from apps.books.models import BookInfo, HeroInfo
from apps.books.serializers import BookSerializer, HeroSerializer, BookModelSerializer, HeroModelSerializer
from rest_framework import mixins, generics
from rest_framework import viewsets

#
# class BooksView(View):
#     def get(self, request):
#         books = BookInfo.objects.all()
#         # blist = []
#         # for book in books:
#         #     blist.append({
#         #         'id':book.id,
#         #         'btitle':book.btitle,
#         #         'bpub_date':book.bpub_date
#         #     })
#         serializer = BookModelSerializer(books, many=True)
#         blist = serializer.data
#         return JsonResponse({'blist': blist})
#
#
# # 查询所有英雄
# class HerosView(View):
#     # 查询所有英雄
#     def get(self, request):
#         heros = HeroInfo.objects.all()
#         # 序列化
#         # serializer = HeroSerializer(heros, many=True)
#         serializer = HeroModelSerializer(heros, many=True)
#         # [{},{},{}]
#         return JsonResponse(serializer.data, safe=False)
#
#     # 创建英雄
#     def post(self, request):
#         json_dict = json.loads(request.body.decode())
#         # 验证
#         # serializer = HeroSerializer(data = json_dict)
#         serializer = HeroModelSerializer(data=json_dict)
#         # 在获取反序列化的数据前，需要调用is_valid()进行验证，验证失败
#         # 可以通过序列化器对象errors属性得到错误信息
#         if not serializer.is_valid():
#             return JsonResponse(serializer.errors, status=400)
#         # 处理  保存创建的数据
#         serializer.save()  # save内部调用create方法
#         # 响应
#         return JsonResponse(serializer.data, status=201)
#
#
# class HeroView(View):
#     def get(self, request, pk):
#         hero = HeroInfo.objects.get(pk=pk)
#         # serializer = HeroSerializer(hero)
#         serializer = HeroModelSerializer(hero)
#         return JsonResponse(serializer.data)
#
#     # 修改英雄属性
#     def put(self, request, pk):
#         try:
#             hero = HeroInfo.objects.get(pk=pk)
#         except:
#             return JsonResponse(status=500)
#         # 接收
#         json_dict = json.loads(request.body.decode())
#         # serializer = HeroSerializer(hero,data=json_dict)
#         serializer = HeroModelSerializer(hero, data=json_dict)
#         if not serializer.is_valid():
#             return JsonResponse(serializer.errors, status=400)
#         # 处理
#         serializer.save()  # save内部会进行判断 update还是create两个方法中的一个
#         return JsonResponse(serializer.data, status=201)
#
#     # 删除某个英雄
#     def delete(self, request, pk):
#         hero = HeroInfo.objects.get(pk=pk)
#         hero.delete()
#         return JsonResponse({}, status=204)


# APIVIew类进行英雄的操作
class HerosAPIView(APIView):
    def get(self, request):
        heros = HeroInfo.objects.all()

        serializer = HeroModelSerializer(heros, many=True)
        return Response(serializer.data)

    def post(self, request):
        json_dict = request.data

        serializer = HeroModelSerializer(data=json_dict)
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=201)


class HeroAPIView(APIView):
    def get(self, request, pk):
        try:
            hero = HeroInfo.objects.get(pk=pk)
        except:
            return Response(status=404)
        serializer = HeroModelSerializer(hero)
        return Response(serializer.data)

    # 修改数据 需要验证数据
    def put(self, request, pk):
        try:
            hero = HeroInfo.objects.get(pk=pk)
        except:
            return Response(status=404)
        json_dict = request.data
        serializer = HeroModelSerializer(hero, data=json_dict)
        # 验证数据 数据不满足时 抛出异常结果
        serializer.is_valid(raise_exception=True)
        serializer.save()
        return Response(serializer.data, status=201)

    def delete(self, request, pk):
        try:
            hero = HeroInfo.objects.get(pk=pk)
            hero.delete()
        except:
            return Response(status=404)
        return Response({}, status=204)


# GenericAPIView类进行英雄操作  GenericAPIView类继承于APIView类
# mixins.ListModelMixin里面封装了 HeroAPIView里面的对于增删改查的操作
# 但是需要指定两个属性  get_queryset指定查询集  serializer指定的序列化器类型
class HerosGenericView(mixins.ListModelMixin, mixins.CreateModelMixin, generics.GenericAPIView):
    queryset = HeroInfo.objects.filter(pk__lt=4)
    serializer_class = HeroModelSerializer

    def get(self, request):
        return self.list(request)

    def post(self, request):  # 通过,mixins.CreateModelMixin里面的擦做完成
        return self.create(request)


class HeroGenericView(mixins.RetrieveModelMixin, mixins.DestroyModelMixin, mixins.UpdateModelMixin,
                      generics.GenericAPIView):
    queryset = HeroInfo.objects.all()
    serializer_class = HeroModelSerializer

    def get(self, request, pk):  # RetrieveModelMixin   里面的retrieve 属于单条查询
        return self.retrieve(request, pk)

    def put(self, request, pk):  # mixins.UpdateModelMixin  来源于update和put一样的效果
        return self.update(request, pk)

    def delete(self, request, pk):
        return self.destroy(request, pk)


class HerosGenericAPIView(generics.ListCreateAPIView):
    queryset = HeroInfo.objects.all()   #queryset 列表视图的查询集
    serializer_class = HeroModelSerializer   #视图使用的序列化器


class HeroGenericAPIView(generics.RetrieveUpdateDestroyAPIView):
    queryset = HeroInfo.objects.all()
    serializer_class = HeroModelSerializer

class HeroViewSet(viewsets.ModelViewSet):
    #继承自GenericAPIVIew，同时包括了ListModelMixin、RetrieveModelMixin、
    # CreateModelMixin、UpdateModelMixin、DestoryModelMixin。
    queryset = HeroInfo.objects.all()
    serializer_class = HeroModelSerializer
    filter_fields = ('id','hname')   #django-filter在dev里面的第三方过滤作用

    filter_backends = [OrderingFilter]
    #rest_framework.filters.OrderingFilter过滤器
    #ordering参数指明的排序字段对数据集进行排序
    ordering_fields = ('id',)

    #如果在视图内关闭分页功能，只需在视图内设置
    # pagination_class = None

    @action(methods=['get'],detail=False)
    def say(self,request):
        return Response({'ermsg':'say'})

    @action(methods=['get'], detail=True)
    #detail=True时默认使用r'^heros/(?P<pk>\d+)/$这条路由
    def sing(self, request,pk):
        return Response({'ermsg': 'sing'})

